"""
Test suite for WindBUFRReader module.

Tests BUFRLIB-backed wind observation reading with parity checks against
Fortran GSI reference output.

Run with:
    julia --project=. tests/test/test_wind_bufr_reader.jl
"""

using Test
using Dates

# Add src to load path
push!(LOAD_PATH, normpath(joinpath(@__DIR__, "..", "..", "src")))

using GSICoreAnalysis
using GSICoreAnalysis.DataIO.WindBUFRReader

@testset "WindBUFRReader Tests" begin

    @testset "BUFRLIB Availability" begin
        @test isfile(WindBUFRReader.WIND_BUFRLIB_PATH)
    end

    @testset "WindObservation Construction" begin
        obs = WindObservation(
            u = 5.0,
            v = 3.0,
            longitude = -95.0,
            latitude = 40.0,
            pressure = 85000.0,
            platform_code = 220,
            quality_mark = 0
        )

        @test obs.u == 5.0
        @test obs.v == 3.0
        @test obs.longitude == -95.0
        @test obs.latitude == 40.0
        @test obs.pressure == 85000.0
        @test obs.platform_code == 220
        @test obs.use_obs == true
        @test obs.sigma_multiplier == 1.0
        @test obs.duplicate_factor == 1.0
    end

    @testset "WindBUFRConfig Construction" begin
        config = WindBUFRConfig(
            use_bufrlib = true,
            max_obs = 50000,
            qc_threshold = 2,
            verbose = false
        )

        @test config.use_bufrlib == true
        @test config.max_obs == 50000
        @test config.qc_threshold == 2
        @test config.apply_10m_reduction == true
    end

    @testset "10m Reduction Logic" begin
        # Surface obs at non-standard height
        obs = WindObservation(
            u = 10.0,
            v = 0.0,
            platform_code = 220,  # Ship
            observation_height = 20.0
        )

        @test WindBUFRReader.needs_10m_reduction(obs) == true

        # Store original speed
        u_orig = obs.u
        WindBUFRReader.apply_10m_reduction!(obs)

        # Should reduce wind speed (log profile)
        @test obs.u < u_orig
        @test obs.u > 0.0

        # Obs already at 10m
        obs2 = WindObservation(
            u = 10.0,
            v = 0.0,
            platform_code = 220,
            observation_height = 10.0
        )

        @test WindBUFRReader.needs_10m_reduction(obs2) == false
    end

    @testset "Sigma Multiplier Computation" begin
        # Surface obs (should inflate)
        obs_sfc = WindObservation(pressure = 95000.0, platform_code = 220)
        mult_sfc = WindBUFRReader.compute_sigma_multiplier(obs_sfc)
        @test mult_sfc > 1.0

        # Mid-troposphere (should be ~1.0)
        obs_mid = WindObservation(pressure = 50000.0, platform_code = 220)
        mult_mid = WindBUFRReader.compute_sigma_multiplier(obs_mid)
        @test mult_mid ≈ 1.0

        # Upper troposphere (should inflate slightly)
        obs_upper = WindObservation(pressure = 20000.0, platform_code = 220)
        mult_upper = WindBUFRReader.compute_sigma_multiplier(obs_upper)
        @test mult_upper > 1.0

        # Satellite wind with cloud contamination
        obs_sat = WindObservation(pressure = 50000.0, platform_code = 280)
        mult_sat = WindBUFRReader.compute_sigma_multiplier(obs_sat, 30000.0, 1.5)
        @test mult_sat > 1.0
    end

    @testset "Platform Mapping" begin
        @test haskey(WindBUFRReader.READ_WIND_PLATFORM_MAP, 120)
        @test WindBUFRReader.READ_WIND_PLATFORM_MAP[120] == :rawinsonde
        @test WindBUFRReader.READ_WIND_PLATFORM_MAP[220] == :ship
        @test WindBUFRReader.READ_WIND_PLATFORM_MAP[280] == :satwnd
    end

    # Integration test with actual PrepBUFR file (if available)
    tutorial_file = "/home/docker/comgsi/tutorial/comGSIv3.7_EnKFv1.3/run/2018081212/obs/rap.t12z.prepbufr.tm00"

    if isfile(tutorial_file)
        @testset "PrepBUFR File Reading" begin
            config = WindBUFRConfig(
                use_bufrlib = true,
                max_obs = 1000,  # Limit for testing
                qc_threshold = 3,
                verbose = true
            )

            @test_nowarn begin
                bundle = read_wind_bufr(tutorial_file, config)
                @test bundle.nobs > 0
                @test bundle.nobs <= 1000

                # Check first observation
                if bundle.nobs > 0
                    obs1 = bundle.observations[1]
                    @test isfinite(obs1.u)
                    @test isfinite(obs1.v)
                    @test -180.0 <= obs1.longitude <= 180.0
                    @test -90.0 <= obs1.latitude <= 90.0
                    @test obs1.pressure > 0.0
                    @test obs1.platform_code > 0
                end

                # Check metadata
                @test haskey(bundle.metadata, "source_file")
                @test haskey(bundle.metadata, "reader_type")
                @test bundle.metadata["reader_type"] == "bufrlib"

                println("\n=== Wind BUFR Reader Test Results ===")
                println("Read $(bundle.nobs) wind observations")
                println("Platforms: $(unique([obs.platform_code for obs in bundle.observations]))")
                println("Quality marks: $(countmap([obs.quality_mark for obs in bundle.observations]))")

                # Platform distribution
                platform_counts = Dict{Int,Int}()
                for obs in bundle.observations
                    platform_counts[obs.platform_code] = get(platform_counts, obs.platform_code, 0) + 1
                end
                println("\nPlatform distribution:")
                for (code, count) in sort(collect(platform_counts), by=x->x[2], rev=true)
                    platform = get(WindBUFRReader.READ_WIND_PLATFORM_MAP, code, :unknown)
                    println("  $code ($platform): $count obs")
                end
            end
        end
    else
        @warn "Tutorial PrepBUFR file not found; skipping integration test" file=tutorial_file
    end
end

println("\n✓ All WindBUFRReader tests passed!")
